using System;
using System.Reflection;
using System.Web.UI;
using ControlLibrary.Interfaces;

namespace ControlLibrary.Helpers
{
    internal class HelperBinding
    {
        private static void SetBinding(IDataBinding dataBinding)
        {
            Type typeBind = dataBinding.GetType();
            Type typeDataSource;

            foreach (IDataBoundControl dataBound in dataBinding.DataBindings)
            {
                typeDataSource = dataBound.DataSource.GetType();

                PropertyInfo targetPropertyInfo = typeBind.GetProperty(dataBound.PropertyName);
                PropertyInfo propertyInfoSource = typeDataSource.GetProperty(dataBound.DataMember);

                try
                {
                    targetPropertyInfo.SetValue(dataBinding, propertyInfoSource.GetValue(dataBound.DataSource, null), null);
                }
                catch (ArgumentException)
                {
                    try
                    {
                        targetPropertyInfo.SetValue(dataBinding, Convert.ChangeType(propertyInfoSource.GetValue(dataBound.DataSource, null), targetPropertyInfo.PropertyType), null);
                    }
                    catch (FormatException) { }
                    catch(InvalidCastException) { }
                }
            }
        }

        private static void GetBinding(IDataBinding dataBinding)
        {
            Type typeDataSource = dataBinding.GetType();

            foreach (IDataBoundControl dataBound in dataBinding.DataBindings)
            {
                Type typeBind;

                typeBind = dataBound.DataSource.GetType();

                PropertyInfo targetPropertyInfo = typeBind.GetProperty(dataBound.DataMember);
                PropertyInfo propertyInfoSource = typeDataSource.GetProperty(dataBound.PropertyName);

                try
                {
                    targetPropertyInfo.SetValue(dataBound.DataSource, propertyInfoSource.GetValue(dataBinding, null), null);
                }
                catch (ArgumentException)
                {
                    Type nullType = Nullable.GetUnderlyingType(targetPropertyInfo.PropertyType);
                    try
                    {
                        if (nullType == null)
                        {
                            targetPropertyInfo.SetValue(dataBound.DataSource, Convert.ChangeType(propertyInfoSource.GetValue(dataBinding, null), targetPropertyInfo.PropertyType), null);
                        }
                        else
                        {
                            targetPropertyInfo.SetValue(dataBound.DataSource, Convert.ChangeType(propertyInfoSource.GetValue(dataBinding, null), nullType), null);
                        }
                    }
                    catch (FormatException)
                    {
                        SetDefaultValue(dataBound.DataSource, targetPropertyInfo, nullType);
                    }
                    catch (InvalidCastException)
                    {
                        SetDefaultValue(dataBound.DataSource, targetPropertyInfo, nullType);
                    }
                }
            }
        }

        private static void SetDefaultValue(object obj, PropertyInfo targetPropertyInfo, Type nullType)
        {
            if(nullType == null)
            {
                targetPropertyInfo.SetValue(obj, Activator.CreateInstance(targetPropertyInfo.PropertyType), null);
            }
            else
            {
                targetPropertyInfo.SetValue(obj, null, null);
                
            }
        }

        public static void DataBind(IDataBinding dataBinding, Page page)
        {
            if (!page.IsPostBack)
            {
                SetBinding(dataBinding);
                GetBinding(dataBinding);
            }
            else
            {
                GetBinding(dataBinding);
                SetBinding(dataBinding);
            }
        }
    }
}